Elasticsearch 的 Dynamic Field Mapping 注意事項
TLDR
- 正式環境強烈建議使用 Explicit Mapping(明確對應),避免使用 Dynamic Mapping。
- 動態對應會自動將字串建立為
text與keyword雙重索引,導致儲存空間大幅膨脹。 - 特殊型別(如
geo_point、nested)與自訂分析器無法透過動態對應自動處理,必須手動定義。 - 動態對應容易引發 Mapping Explosion,導致欄位數量超過預設限制(1000 個),進而影響記憶體與效能。
- 建議根據需求調整
dynamic參數:開發期可用true,正式環境建議視情況改為false或strict。
動態欄位對應的誤區與風險
Elasticsearch 的 Dynamic Mapping 功能雖然方便,但在生產環境中隱藏了許多潛在問題。以下分析常見的踩雷情境與原因:
1. 字串型別導致儲存空間膨脹
什麼情況下會遇到: 當系統自動將字串欄位建立索引時。
- 原因分析:預設情況下,Elasticsearch 會將字串同時儲存為
text(用於全文檢索)與keyword(用於精確比對、排序與聚合)的子欄位。這種雙重索引會導致儲存空間倍增。 - 建議做法:若非必要,應明確定義欄位型別,避免不必要的索引開銷。
2. 進階功能無法自動對應
什麼情況下會遇到: 當需要使用地理查詢、巢狀物件或自訂分詞時。
- 原因分析:
- 地理位置:若未預先定義為
geo_point或geo_shape,資料會被視為普通object,導致無法使用geo_distance等地理查詢功能。 - 巢狀物件:動態對應會將陣列物件扁平化為
object,導致無法正確查詢陣列內部的獨立物件。 - 自訂分析器:動態對應僅會使用預設的
standard analyzer,無法套用中文分詞或同義詞處理。
- 地理位置:若未預先定義為
- 建議做法:針對特定查詢需求,必須在 Mapping 中明確指定型別與
analyzer。
3. Mapping Explosion 風險
什麼情況下會遇到: 當資料來源包含大量動態產生的 Key 或使用者自訂欄位時。
- 原因分析:動態對應會不斷新增欄位到 Index 中,若欄位數量超過預設的 1000 個限制,系統將拒絕寫入新文件,並導致記憶體使用量激增。
- 建議做法:對於結構不固定的資料,應考慮使用
false或strict設定來限制自動對應。
Dynamic Mapping 型別對應規則
Elasticsearch 根據 JSON 資料型別進行自動對應的規則如下:
| JSON 資料型別 | Elasticsearch 型別 ("dynamic":"true") | Elasticsearch 型別 ("dynamic":"runtime") |
|---|---|---|
null | 不新增欄位 | 不新增欄位 |
true 或 false | boolean | boolean |
double | float | double |
long | long | long |
object | object | 不新增欄位 |
array | 取決於陣列中第一個非 null 值 | 取決於陣列中第一個非 null 值 |
通過日期檢測的 string | date | date |
通過數字檢測的 string | float 或 long | double 或 long |
未通過 date 或 numeric 檢測的 string | text 並帶有 .keyword 子欄位 | keyword |
Dynamic 參數設定建議
透過設定 dynamic 參數,可以有效控制 Index 的結構安全性:
true(預設值):新欄位自動加入 Mapping。僅適合開發階段快速測試。runtime:新欄位以 Runtime fields 加入,不佔用索引空間,但查詢效能較差,適合不常查詢的欄位。false:忽略新欄位。欄位不會被索引或搜尋,但仍存在於_source中。可有效防止 Mapping Explosion。strict:最嚴格模式。偵測到新欄位即拋出例外並拒絕寫入,適合需要嚴格 Schema 控制的正式環境。
總結
在正式環境中,應避免過度依賴 Dynamic Mapping。事先規劃並明確定義 Schema,不僅能優化儲存空間與查詢效能,還能避免日後因 Mapping 變更而必須進行昂貴的 Reindex 操作。
異動歷程
- 初版文件建立。